package org.neu.ccs.secureim;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.codec.binary.Base64;

public class ServerMain {
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
	
		System.out.print("Reading users...");
		
		ConcurrentHashMap<String, ServerUserInfo> users = null;
		try
		{
			users = ReadUsersFile();
		}
		catch(Exception e)
		{
			System.out.println("Error reading users file");
			e.printStackTrace();
			return;
		}
		
		System.out.println("DONE");
		
		System.out.print("Reading configuration...");
		
		//Read connection defaults from properties file
		Properties prop = new Properties();
		try
		{
			FileInputStream fin = new FileInputStream("ServerSettings.properties");
			prop.load(fin);
		}
		catch(IOException e)
		{
			System.out.println("Error reading settings file.");
			e.printStackTrace();
			System.exit(-1);
		}
		
		if( !(prop.containsKey("ServerPubKey") && prop.containsKey("ServerPrivateKey") && prop.containsKey("ServerPort")) )
		{
			System.out.println("Properties file does not contain server settings, please run keygen first.");
			System.exit(-1);
		}
		
		Base64 enc = new Base64();
		X509EncodedKeySpec serverPubKey = new X509EncodedKeySpec(enc.decode((String)prop.get("ServerPubKey")));
		PKCS8EncodedKeySpec serverPrivateKey = new PKCS8EncodedKeySpec(enc.decode((String) prop.get("ServerPrivateKey")));
		
		KeyPair serverPair = null;
		try {
			KeyFactory kf = KeyFactory.getInstance("RSA");
			serverPair = new KeyPair(kf.generatePublic(serverPubKey), kf.generatePrivate(serverPrivateKey));
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.exit(-1);
		} catch (InvalidKeySpecException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.exit(-1);
		}
		
		int port = Integer.parseInt((String)prop.get("ServerPort"));
		
		System.out.println("DONE");
		
		System.out.print("Starting server...");
		ChatServer serv = new ChatServer(port, serverPair, users);
		Thread mainThread = new Thread(serv);
		mainThread.start();
		System.out.println("DONE");
	}
	
	public static ConcurrentHashMap<String, ServerUserInfo> ReadUsersFile() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException
	{
		ConcurrentHashMap<String, ServerUserInfo> users = new ConcurrentHashMap<String, ServerUserInfo>();

		BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream("Users.conf")));
		
		Base64 enc = new Base64();
		
		String input = r.readLine();
		KeyFactory kf = KeyFactory.getInstance("RSA");
		while( input != null && !input.trim().isEmpty())
		{
			StringTokenizer t = new StringTokenizer(input);
			String username = t.nextToken();
			String salt64 = t.nextToken();
			String pubKey64 = t.nextToken();
			
			byte[] saltBytes = enc.decode(salt64);
			byte[] pubKeyBytes = enc.decode(pubKey64);
			
			PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
			
			ServerUserInfo inf = new ServerUserInfo(null, 0, pubKey, username, saltBytes);
			users.put(username, inf);
			
			input = r.readLine();
		}
		
		return users;
	}

}
